/**
 * 开源版本请务必保留此注释头信息，若删除捷码开源〔GEMOS〕官方保留所有法律责任追究！
 * 本软件受国家版权局知识产权以及国家计算机软件著作权保护（登记号：2018SR503328）
 * 不得恶意分享产品源代码、二次转售等，违者必究。
 * Copyright (c) 2020 gemframework all rights reserved.
 * http://www.gemframework.com
 * 版权所有，侵权必究！
 */
package com.gemframework.common.utils.security;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;

/**
 * @Title: GemCryptos
 * @Package: com.gemframework.common.utils
 * @Date: 2020-06-26 23:43:11
 * @Version: v1.0
 * @Description: 加密工具
 * @Author: nine QQ 769990999
 * @Copyright: Copyright (c) 2020 wanyong
 * @Company: www.gemframework.com
 */
@Slf4j
public class GemCryptosUtils {
    private static final String DEFAULT_URL_ENCODING = "UTF-8";
    private static final String AES = "AES";
    private static final String AES_CBC = "AES/CBC/PKCS5Padding";
    private static final String HMACSHA1 = "HmacSHA1";
    private static final int DEFAULT_HMACSHA1_KEYSIZE = 160;
    private static final int DEFAULT_AES_KEYSIZE = 128;
    private static final int DEFAULT_IVSIZE = 16;
    private static SecureRandom random = new SecureRandom();

    public GemCryptosUtils() {
    }

    /**
     * HMACSHA1签名算法
     * @param encryptText
     * @param encryptKey
     * @return
     */
    public static String hmacSha1(String encryptText, String encryptKey) {
        try {
            //将密钥转换为utf-8编码的byte型数据
            byte[] key = encryptKey.getBytes(DEFAULT_URL_ENCODING);
            //将加密字符串转换为utf-8编码的byte型数据
            byte[] input= encryptText.getBytes(DEFAULT_URL_ENCODING);
            SecretKey secretKey = new SecretKeySpec(key, HMACSHA1);
            Mac mac = Mac.getInstance(HMACSHA1);
            mac.init(secretKey);
            return byteArrayToHex(mac.doFinal(input));
        } catch (GeneralSecurityException | UnsupportedEncodingException var4) {
            log.error(var4.getMessage());
            return null;
        }
    }

    /**
     * 16进制加密
     * @param a
     * @return
     */
    public static String byteArrayToHex(byte [] a) {
        int hn, ln, cx;
        String hexDigitChars = "0123456789abcdef";
        StringBuffer buf = new StringBuffer(a.length * 2);
        for(cx = 0; cx < a.length; cx++) {
            hn = ((int)(a[cx]) & 0x00ff) /16 ;
            ln = ((int)(a[cx]) & 0x000f);
            buf.append(hexDigitChars.charAt(hn));
            buf.append(hexDigitChars.charAt(ln));
        }
        return buf.toString();

    }

    public static boolean isMacValid(byte[] expected, String input, String key) {
        byte[] actual = hmacSha1(input, key).getBytes();
        return Arrays.equals(expected, actual);
    }


    public static byte[] generateHmacSha1Key() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1);
            keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE);
            SecretKey secretKey = keyGenerator.generateKey();
            return secretKey.getEncoded();
        } catch (GeneralSecurityException var2) {
            log.error(var2.getMessage());
            return null;
        }
    }

    /**
     * AES签名算法
     * @param input
     * @param key
     * @param mode
     * @return
     */
    private static byte[] aes(byte[] input, byte[] key, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, AES);
            Cipher cipher = Cipher.getInstance(AES);
            cipher.init(mode, secretKey);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException var5) {
            log.error(var5.getMessage());
            return null;
        }
    }

    private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, AES);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance(AES_CBC);
            cipher.init(mode, secretKey, ivSpec);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException var7) {
            log.error(var7.getMessage());
            return null;
        }
    }


    public static byte[] aesEncrypt(byte[] input, byte[] key) {
        return aes(input, key, 1);
    }

    public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) {
        return aes(input, key, iv, 1);
    }

    public static String aesDecrypt(byte[] input, byte[] key) {
        byte[] decryptResult = aes(input, key, 2);
        return new String(decryptResult);
    }

    public static String aesDecrypt(byte[] input, byte[] key, byte[] iv) {
        byte[] decryptResult = aes(input, key, iv, 2);
        return new String(decryptResult);
    }

    public static byte[] generateAesKey() {
        return generateAesKey(DEFAULT_AES_KEYSIZE);
    }

    public static byte[] generateAesKey(int keysize) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(keysize);
            SecretKey secretKey = keyGenerator.generateKey();
            return secretKey.getEncoded();
        } catch (GeneralSecurityException var3) {
            log.error(var3.getMessage());
            return null;
        }
    }

    public static byte[] generateIV() {
        byte[] bytes = new byte[DEFAULT_IVSIZE];
        random.nextBytes(bytes);
        return bytes;
    }
}
